


namespace Orz.LogManager 
{
	//========================================================================
	// 	Imported Namespaces
	//========================================================================
	using System;
	using System.Windows.Forms;
	using System.IO;
	using System.Drawing;
	using System.Collections;
	using System.Runtime.InteropServices;
	using Orz.Gui.Forms;
	

	///
	/// <summary>
	/// Represents a window displaying updates on an individual log file.
	/// </summary>
	/// <remarks>
	/// This class contains the functionality for a window that can open,
	/// tail, copy and save the contents of an individual log file.
	/// It will work as the MDI child of a <code>MainForm</code> window.
	/// </remarks>
	///
	public abstract class LoggingBaseForm : System.Windows.Forms.Form
	{
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.ToolBar toolBar1;
		private System.Windows.Forms.ToolBarButton tbbSep2;
		private System.Windows.Forms.Timer timer;
		private System.Windows.Forms.MenuItem miPause;
		private System.Windows.Forms.ToolBarButton tbbScrollLock;
		private System.Windows.Forms.MenuItem miReload;
		private System.Windows.Forms.MenuItem miClose;
		private System.Windows.Forms.ToolBarButton tbbUnpause;
		private System.Windows.Forms.MenuItem menuItem3;
		private System.Windows.Forms.MenuItem miCopy;
		private System.Windows.Forms.ToolBarButton tbbClear;
		private System.Windows.Forms.MenuItem menuItem5;
		private System.Windows.Forms.Timer sleepTimer;
		private System.Windows.Forms.MenuItem miSave;
		private System.Windows.Forms.MenuItem menuItem8;
		private System.Windows.Forms.ToolBarButton tbbPause;
		private System.Windows.Forms.Panel panel2;
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.ToolBarButton tbbFilter;
		private System.Windows.Forms.ContextMenu contextMenu;
		private System.Windows.Forms.ToolBarButton tbbSep1;
		private System.Windows.Forms.MenuItem miClear;
		private System.Windows.Forms.ImageList imageList1;
		
		
		
		private SpecialRichTextBox txtLog;
		
		//================================================================
		// 	Private Data Members
		//	Most of these have been auto-generated for the GUI
		//================================================================		
		
		/// <summary>A stream providing data from the log file</summary>
		protected ILogManagerStream stream_i;
		
		/// <summary>A list of possible filters to be applied to each line</summary>
		protected ArrayList oLineMatches_i = new ArrayList();
		
		/// <summary>A flag used to indicate whether to convert CR/LF characters</summary>
		protected bool bUnixEncoding_i = false;
		
		/// <summary>A flag to indicate that the form would like to close</summary>
		protected bool bClosing_i = false;
		
		/// <summary>The unique name that has been given to this window, based on the log file name</summary>
		protected string sName_i;
		
		/// <summary>The maximum number of chars to display in this window before panicking</summary>
		protected int iMaxCharsPerWindow_i = MAX_TEXT;
				
		/// <summary>A flag to force the window to close</summary>
		protected bool bForceClose_i = false;
		
		/// <summary>A panel that can be used to take the focus off the main textbox</summary>
		protected System.Windows.Forms.Panel dummyPanel;
		
		/// <summary>A flag to say whether the contents have been truncated to save memory</summary>
		protected bool bTruncated_i = false;
		
		/// <summary>A flag to say whether new lines are being filtered</summary>
		protected bool bFiltered_i = false;
		
		/// <summary>Sleepy if there's been no input for a while</summary>
		protected bool isSleepy_i = false;
		
		/// <summary>Set to true to stop it scrolling every line</summary>
		protected bool isScrollLocked_i = false;
		
		/// <summary>Stores the appropriate icon for the datasource (local/telnet/ssh/etc)</summary>
		protected Icon defaultIcon_i;
		
		/// <summary>Stores the icon we display when we're sleepy</summary>
		protected Icon sleepyIcon_i;
		
		/// <summary>The linefeed character to be stripped if <code>bUnixEncoding_i</code> is <code>true</code></summary>
		protected static string LINE_FEED_CHARACTER_c = Convert.ToString((char)0x0A);
		
		/// <summary>Windows vertical scroll message id for the <code>SendMessage</code> command</summary>
		protected const int WM_VSCROLL = 0x115; 
		
		/// <summary>Windows horizontal scroll message id for the <code>SendMessage</code> command</summary>
		protected const int WM_HSCROLL = 0x114;
		
		/// <summary>'Scroll-to-bottom' constant for the <code>WM_VSCROLL</code> message</summary>
		protected const int SB_BOTTOM = 7;
		
		/// <summary>'Scroll-to-left' constant for the <code>WM_HSCROLL</code> message</summary>
		protected const int SB_LEFT = 6;
		
		/// <summary>The maximum number of chars to display before clearing</summary>
		protected const int MAX_TEXT = 200000;
		
		/// <summary>ImageList index for an icon to represent a 'local' file</summary>
		protected const int IMG_LOCAL_FILE = 0;
		
		/// <summary>ImageList index for an icon to represent a 'telnet' file</summary>
		protected const int IMG_TELNET_FILE = 1;

		/// <summary>ImageList index for an icon to represent an 'ssh' file</summary>
		protected const int IMG_SSH_FILE = 8;
		
		/// <summary>ImageList index for an icon to represent 'sleepyness'</summary>
		protected const int IMG_SLEEPY = 9;
		
		/// <summary>How long (ms) without input before we decide that we're sleepy?</summary>
		protected const int SLEEPY_TIMEOUT = 60000;
		
		
		//================================================================
		// 	External dll references
		//================================================================
		[DllImport("user32.dll")] 
		public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
        
		
		
		
		
		//================================================================
		// 	Constructors
		//================================================================

		///
		/// <summary>
		/// Initialises the window's child controls.
		/// </summary>
		///
		public LoggingBaseForm(string sName_p, ILogManagerStream stream_p)
		{
			stream_i = stream_p;
			this.sName_i = sName_p;
			InitializeComponent();
			InitializeComponent2();
			UpdateTitle();
		}
		
		
		
		
		
		
		
		
		//================================================================
		// 	Properties
		//================================================================

		///
		/// <summary>
		/// Specifies a unique name for this form.
		/// </summary>
		/// <remarks>
		/// The name should be based on the log-file name specified in the
		/// configuration file.
		/// </remarks>
		///		
		public new string Name
		{
			get 
			{ 
				return this.sName_i; 
			}
			/*set 
			{
				this.sName_i = value;
				UpdateTitle();
				//this.Text = value;				
			}*/
		}
		
		///
		/// <summary>
		/// The maximum number of characters that should be displayed at any
		/// one time in the log window.
		/// </summary>
		/// <remarks>
		/// If the number of chars in the window goes above this level we should 
		/// take some action.
		/// </remarks>
		///		
		public int MaxCharsPerWindow
		{
			get
			{
				return this.iMaxCharsPerWindow_i;
			}
			set
			{
				this.iMaxCharsPerWindow_i = value;
			}
		}
		
		///
		/// <summary>
		/// Specifies whether to strip CR/LF characters from the input.
		/// </summary>
		/// <remarks>
		/// If this is set to true then unix-style line-feeds will be replaced with the
		/// standard Windows <code>"\n"</code> line-feeds.  The default is <code>false</code>.
		/// </remarks>
		///		
		public bool UnixEncoding
		{
			get
			{
				return this.bUnixEncoding_i;
			}
			set 
			{
				this.bUnixEncoding_i = value;
			}
		}
		
		
		
		public bool ScrollLocked
		{
			get 
			{ 
				return this.isScrollLocked_i;
			}
			set
			{
				this.isScrollLocked_i = value;
			}
		}
		
		
		
		
		///
		/// <summary>
		/// Specifies whether the contents of the textbox have been automatically truncated
		/// to save memory and processing time.
		/// </summary>
		/// <remarks>
		/// This is set to true when the number of chars in the textbox exceeds the limit set in
		/// <code>MaxCharsPerWindow</code>.  It will be unset whenever the contents of the textbox
		/// are cleared.
		/// </remarks>
		///		
		public bool Truncated
		{
			get
			{
				return this.bTruncated_i;
			}
			set 
			{
				this.bTruncated_i = value;
			}
		}
		
		
		
		
		///
		/// <summary>
		/// Specifies whether new lines that are added are being filtered.
		/// </summary>
		///		
		public bool Filtered
		{
			get
			{
				return this.bFiltered_i;
			}
			set 
			{
				this.bFiltered_i = value;
			}
		}


		///
		/// <summary>
		/// Has a value of <code>true</code> if the timer is started and updates are being
		/// processed.
		/// </summary>
		///		
		public bool Started
		{
			get
			{
				return (timer.Enabled);
			}
		}
		
		
		
		
		

		
		//================================================================
		// 	Methods
		//================================================================

		
		
		protected abstract Icon GetDefaultIcon();
		
		
		protected Icon MakeIcon (Image image_p)
		{		
			Image i = imageList1.Images[0];
			Bitmap b = (Bitmap) image_p;		
			return Icon.FromHandle(b.GetHicon());			
		}
		
		
		
		///
		/// <summary>
		/// Associates a line filter with this logging window.
		/// </summary>
		/// <remarks>
		/// The line filter will be applied to each line that is read in from the
		/// input stream.
		/// </remarks>		
		///		
		public void AddLineMatch (LineMatch oLineMatch_p)
		{
			oLineMatches_i.Add (oLineMatch_p);
		}
		
		
		
		///
		/// <summary>
		/// Prepares the window for shutdown.
		/// </summary>
		/// <remarks>
		/// This method should be called before closing the window.  It stops the
		/// update timer and closes the file stream (if it exists).
		/// </remarks>		
		///		
		public void Deinitialise ()
		{
			try
			{
				//MessageBox.Show("Deinitialising " + this.Text);
				StopTimer();
			
				if (null != stream_i)
				{
					stream_i.Close();
					stream_i = null;
				}
			}
			catch (Exception e)
			{
				// Not much we can do here!
			}
		}
		
		
		
		///
		/// <summary>
		/// Returns the image from the main image list for children to use.
		/// </summary>
		/// 
		protected Image GetImage(int iIndex_p)
		{
			return imageList1.Images[iIndex_p];
		}
		
		
		
		
		/// 
		/// <summary>
		/// Copies all the text (text-only, not rtf!) from the window into the 
		/// given output stream.
		/// </summary>
		/// 
		public bool DumpText (System.IO.Stream stream_p)
		{
			try
			{
				StreamWriter sw = new StreamWriter(stream_p);
				sw.Write (txtLog.Text);
				return true;
			}
			catch (Exception e)
			{
				return false;
			}
		
		}
		
		
		///
		/// <summary>
		/// Attempts to save the contents of the window to a file.
		/// </summary>
		/// <param name="sFile_p">The filename to save to.</param>
		/// <param name="bOverwrite_p">If this is set to <code>true</code>, the file will be overwritten if it already exists.</param>
		/// <remarks>
		/// The window contents are saved in plain text format.
		/// </remarks>		
		///		
		public bool DoSave (String sFile_p, bool bOverwrite_p)
		{
			try
			{
				txtLog.SaveFile(sFile_p, RichTextBoxStreamType.PlainText);
				return true;
			}
			catch (IOException ioe1)
			{
				if (bOverwrite_p)
				{
					try
					{
						File.Delete (sFile_p);
						txtLog.SaveFile (sFile_p, RichTextBoxStreamType.PlainText);
						return true;
					}
					catch (IOException ioe2)
					{
						return false;
					}
				}
				else
				{
					return false;
				}
			}
		}
		
		
		
		
		///
		/// <summary>
		/// Copies part or all of the window text to the clipboard.
		/// </summary>
		/// <param name="bSelectionOnly_p">If this is <code>true</code> then only the selected text will be copied.</param>
		///		
		public void DoCopy (bool bSelectionOnly_p)
		{
			if (!bSelectionOnly_p)
			{
				txtLog.SelectAll();
			}
			txtLog.Copy();
		}
		
		
		
		
		///
		/// <summary>
		/// Performs a search-and-highlight on the log's text box, based on the details
		/// given in <code>finder_p</code>.  The pattern used is the currently selected
		/// text.
		/// </summary>
		/// <param name="finder_p">The find criteria to use.</param>
		/// <param name="bShowDialog_p">True if a "Find" dialog should be displayed first.</param>
		/// <returns>True if a match was found, or the process was cancelled.</returns>
		///		
		public bool DoFind (Finder finder_p, bool bShowDialog_p)
		{
			if (txtLog.SelectedText.Length > 0)
			{
				finder_p.Pattern = txtLog.SelectedText;
			}
		    
			if (bShowDialog_p)
			{
			    FindForm f = new FindForm (finder_p);
			    if (DialogResult.Cancel == f.ShowDialog()) return true;
			}
			    
			return finder_p.Find (txtLog);									
		}
		
		
		
		
		
		///
		/// <summary>
		/// Performs a filter on the log's text box, based on the details
		/// given in <code>filterer_p</code>.  The pattern used is the currently selected
		/// text.
		/// </summary>
		/// <param name="filterer_p">The filter criteria to use.</param>
		/// <param name="bShowDialog_p">True if a "Filter" dialog should be displayed first.</param>
		///		
		public void DoFilter (Filterer filterer_p, bool bShowDialog_p)
		{
			if (txtLog.SelectedText.Length > 0)
			{
				filterer_p.Pattern = txtLog.SelectedText;
			}
		    
			if (bShowDialog_p)
			{
			    FilterForm f = new FilterForm (filterer_p);
			    if (DialogResult.Cancel == f.ShowDialog()) return;
			}
			    
			filterer_p.Filter (txtLog);
		}
		
		
		
		///
		/// <summary>
		/// Starts the update timer.
		/// </summary>
		/// 
		public void DoStart()
		{
			//this.Text = sName_i;
			UpdateTitle();
			DoUpdate();
			StartTimer();
		}
		
		
		
		///
		/// <summary>
		/// Starts the update timer.
		/// </summary>
		/// 
		public void DoStart(bool bUpdate_p)
		{
			UpdateTitle();
			//this.Text = sName_i;
			
			if (bUpdate_p)
			{
				DoUpdate();
			}
			
			StartTimer();
		}
		
		
		
		///
		/// <summary>
		/// Stops the update timer.
		/// </summary>
		/// 
		public void DoStop()
		{
			StopTimer();
			UpdateTitle();
		}
		
		
		
		protected void UpdateTitle()
		{
			string sTitle = sName_i;
			if (Truncated)      sTitle += " [truncated]";
			if (!timer.Enabled) sTitle += " - stopped";
				
			this.Text = sTitle;
			
			if (isSleepy_i)
			{
				this.Icon = sleepyIcon_i;
			}
			else
			{
				this.Icon = defaultIcon_i;
			}
			
			tbbPause.Visible = this.Started;
			tbbUnpause.Visible = !this.Started;
			
			miPause.Text = (this.Started ? "&Stop" : "&Start");
			
			
			
		}
		
		
		
		///
		/// <summary>
		/// Clears the contents of the window.
		/// </summary>
		/// <remarks>
		/// Note that this will not affect the contents of the file in any way.
		/// </remarks>
		///		
		public void DoClear()
		{
			txtLog.Clear();
			Truncated = false;
			UpdateTitle();
		}
		
		
		
		///
		/// <summary>
		/// Attempts to close the window.
		/// </summary>
		/// <param name="bForce_p">If this is set to <code>false</code> then the user will be asked if they really want to close the window.</param>
		///		
		public bool DoClose(bool bForce_p)
		{
			bForceClose_i = bForce_p;
			bClosing_i = false;
			this.Close();
			return (bClosing_i);
		}
		
		
		
		///
		/// <summary>
		/// Displays the entire log-file from the start.
		/// </summary>
		/// <param name="bParse_p">Specifies whether or not to perform filtering on each line.</param>
		///		
		public void DoReload(bool bParse_p)
		{
			bool bWasPaused = timer.Enabled;
			
			StopTimer();
			stream_i.SeekToStart();	
			DoClear();			
			Truncated=false;	
			DoUpdate(bParse_p, false);			
			
			if (stream_i is TelnetFileStream  ||  ! bWasPaused) StartTimer();
		}
		
		
		
		
		
		
		
		
		
		
		
		
		///
		/// <summary>
		/// Starts the timer and sets the Pause menu item's caption.
		/// </summary>
		///		
		protected void StartTimer()
		{
			timer.Start();
			//sleepTimer.Start();
			
			UpdateTitle();
		}
		
		
		
		///
		/// <summary>
		/// Stops the timer and sets the Pause menu item's caption.
		/// </summary>
		///		
		protected void StopTimer()
		{
			timer.Stop();
			sleepTimer.Stop();		
			UpdateTitle();
		}
		
		
		
		///
		/// <summary>
		/// Expands the text field to fill the window.
		/// </summary>
		///		
		protected void DoResize ()
		{
			txtLog.Height = this.ClientSize.Height;
			txtLog.Width = this.ClientSize.Width;
		}
		
		
		
		///
		/// <summary>
		/// Displays 
		/// </summary>
		/// <remarks>
		/// Note that this will not affect the contents of the file in any way.
		/// </remarks>
		///		
		protected void DoUpdate()
		{
			DoUpdate (true);
		}
			
		
		
		///
		/// <summary>
		/// Reads any new lines from the file stream and displays them.  Will be truncated if necessary.
		/// </summary>
		/// <param name="bParse_p">Specifies whether or not to perform filtering on each line.</param>
		///		
		protected void DoUpdate(bool bParse_p)
		{
			DoUpdate (bParse_p, true);			
		}
		
		
		
		
		
		///
		/// <summary>
		/// Reads any new lines from the file stream and displays them.  Will be truncated if requested.
		/// </summary>
		/// <param name="bParse_p">Specifies whether or not to perform filtering on each line.</param>
		///		
		protected void DoUpdate (bool bParse_p, bool bTruncate_p)
		{
			int iLength = this.txtLog.Text.Length;
			
			// original: this.txtLog.AllowPaint = false;
			
			//================================================================
			// If the file is getting too big, chop the first third off it.
			//================================================================
			if (bTruncate_p  &&  (iLength/1024) > iMaxCharsPerWindow_i)
			{
				this.txtLog.Select(0, iLength / 3);
				this.txtLog.SelectedText = "";
				this.txtLog.Select (txtLog.Text.Length, 0);
				Truncated=true;
				UpdateTitle();
			}
			
			try
			{				
				//================================================================
				// If this is the active window, set the focus to the dummy panel
				// to prevent annoying update behaviour.
				//================================================================
				MainForm oParent = (MainForm) this.MdiParent;			
				// original: if (null != oParent  &&  null != oParent.ActiveMdiChild  &&  oParent.ActiveMdiChild.Text.Equals(this.Text))
				{
				// original: this.dummyPanel.Show();
				// original: this.dummyPanel.Focus();
				}
				
				String sFileString = stream_i.ReadToEnd();
				WriteLines(sFileString, bParse_p);											
			}
			catch (IOException ioe)
			{
				DoStop();
				MessageBox.Show ("Error updating " + sName_i);
			}
			finally
			{
				// original: this.dummyPanel.Hide();
				// original: this.txtLog.AllowPaint = true;
			}
		}
		
		
		
		
		
		///
		/// <summary>
		/// Writes the given lines of text to the textbox.
		/// </summary>
		/// <param name="sNewInput_p">Any number of lines to be displayed.</param>
		/// <param name="bParse_p">Specifies whether or not to perform filtering on each line.</param>
		/// <remarks>
		/// This method performs CR/LF conversion if necessary, parses each line if required and
		/// writes the output to the textbox.
		/// </remarks>
		///		
		protected void WriteLines(string sNewInput_p, bool bParse_p)
		{
			bool bWroteSomething = false;
			
			if (bUnixEncoding_i)
			{				
				sNewInput_p.Replace(LINE_FEED_CHARACTER_c, "\n");
			}
			
			if (sNewInput_p.Length > 0)
			{
				bool bWasSleepy = isSleepy_i;
				isSleepy_i = false;
				sleepTimer.Stop();
				sleepTimer.Start();
				
				if (bWasSleepy)
				{
					UpdateTitle();
				}
			}
					
			
			if (bParse_p)
			{
				string[] vsLines = sNewInput_p.Split('\n');
				
				Color oCurrentColour = Color.LightGray;
				IList linesToWrite = new ArrayList();
				
				foreach (string sLine in vsLines)
				{
					if (sLine.Length > 0)
					{
						Color oFinalColour = Color.LightGray;
						String sFinalLine = sLine;
						
						// Do any pattern matching/colouring on this line
						foreach (LineMatch oLineMatch in oLineMatches_i)
						{
							Color oThisColour = oLineMatch.MatchColour(sLine);
							sFinalLine = oLineMatch.DoReplacement(sFinalLine);
							
							if (!oThisColour.IsEmpty)
							{
								oFinalColour = oThisColour;
							}
						}
						
						if (oFinalColour != oCurrentColour)
						{
							if (DumpLinesToTextBox (linesToWrite, oCurrentColour))
							{
								bWroteSomething = true;
							}
							
							oCurrentColour = oFinalColour;
							linesToWrite = new ArrayList();
						}
						
						if (sFinalLine.Length > 0)
						{
							linesToWrite.Add (sFinalLine);
						}
					}
				}
				
				if (linesToWrite.Count > 0)
				{
					if (DumpLinesToTextBox (linesToWrite, oCurrentColour))
					{
						bWroteSomething = true;
					}
				}
			}
			else
			{
				if (sNewInput_p.Length > 0)
				{
					txtLog.Text = sNewInput_p;
					txtLog.SelectAll();
					txtLog.SelectionColor = Color.LightGray;
					txtLog.Select(sNewInput_p.Length + 1, 0);
					bWroteSomething = true;
				}
			}
				
			if (bWroteSomething)
			{				
				DoScroll();
			}
		}
		
		
		
		
		
		protected bool DumpLinesToTextBox (IList linesToDump_p, Color newColour_p)
		{
			bool bWroteSomething = false;
			

			System.Text.StringBuilder sbTextToWrite = new System.Text.StringBuilder();
			
			foreach (string sBufferedLine in linesToDump_p)
			{
				sbTextToWrite.Append (sBufferedLine);
				sbTextToWrite.Append ("\n");
			}
			
			if (sbTextToWrite.Length > 0)
			{
				this.txtLog.AllowPaint = false;
				
				Form parent = this.MdiParent;
				
				//if (isScrollLocked_i && null != parent  &&  null != parent.ActiveMdiChild  &&  parent.ActiveMdiChild.Text.Equals(this.Text))
				if (isScrollLocked_i)
				{
					txtLog.HideSelection = true;
					
						this.dummyPanel.Show();
						this.dummyPanel.Focus();
				}
				else if (null != parent  &&  null != parent.ActiveMdiChild  &&  parent.ActiveMdiChild.Text.Equals(this.Text))
				{					
					//this.dummyPanel.Show();
					//this.dummyPanel.Focus();
				}
				else
				{
					txtLog.HideSelection = false;
					
					this.dummyPanel.Show();
					this.dummyPanel.Focus();
				}
				
				txtLog.SelectionStart = txtLog.Text.Length;
				// original: txtLog.Select (txtLog.Text.Length, 0);
				txtLog.SelectionColor = newColour_p;
				
				txtLog.SelectedText = sbTextToWrite.ToString();
				// original: txtLog.AppendText (sbTextToWrite.ToString());
				
				//txtLog.Select (txtLog.Text.Length, 0);
				
				if (! isScrollLocked_i)
				{
					this.dummyPanel.Hide();
				}
				
				this.txtLog.AllowPaint = true;
			
				
				bWroteSomething = true;
			}
			
			//txtLog.Select (txtLog.Text.Length, 0);
			
			return bWroteSomething;
		}
		
		
		
		
		
		
		// THIS METHOD IS MAINTAINED BY THE FORM DESIGNER
		// DO NOT EDIT IT MANUALLY! YOUR CHANGES ARE LIKELY TO BE LOST
		
		///
		/// <summary>
		/// Creates extra controls for the form and starts the updates.
		/// </summary>
		///		
		protected void CreatedFormLoad(object sender, System.EventArgs e)
		{
			CreateExtraControls();
			DoResize();
			DoUpdate();
			StartTimer();
		}
		
		
		
		
		
		///
		/// <summary>
		/// Handles close requests for the form.
		/// </summary>
		/// <remarks>
		/// If the <code>bForceClose_i</code> flag is set to false then the user will be asked to 
		/// confirm the close request.  If the close is ok'd then all processing of the files will
		/// cease.
		/// </remarks>
		///		
		protected void CreatedFormClosing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if (bForceClose_i  ||  DialogResult.Yes == MessageBox.Show ("Are you sure you want to close this file?", sName_i, MessageBoxButtons.YesNo))
			{
				Deinitialise();
				bClosing_i = true;
			}
			else
			{				
				e.Cancel = true;
				bClosing_i = false;
			}
			bForceClose_i = false;
		}
		
		
		
		///
		/// <summary>
		/// Updates the screen with each timer event.
		/// </summary>
		///		
		protected void TimerTick(object sender, System.EventArgs e)
		{
			DoUpdate();
		}
		
		
		///
		/// <summary>
		/// Makes sure the textbox fills the window.
		/// </summary>
		///		
		protected void LoggingBaseFormResize(object sender, System.EventArgs e)
		{
			DoResize();
		}
		
		
		
		///
		/// <summary>
		/// Calls the <code>DoCopy</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiCopyClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoCopy(true);
		}
		
		
		///
		/// <summary>
		/// Calls the <code>DoClear</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiClearClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoClear();
		}
		
		
		///
		/// <summary>
		/// Calls the <code>DoPause</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiPauseClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoPause();
		}
		
		
		///
		/// <summary>
		/// Calls the <code>DoSave</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiSaveClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoSave();
		}
		
		
		///
		/// <summary>
		/// Calls the <code>DoReload</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiReloadClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoReload();
		}
		
		
		///
		/// <summary>
		/// Calls the <code>DoClose</code> command on the parent window.
		/// </summary>
		/// <remarks>
		/// This call is made to the parent MDI form in order to re-use
		/// code.
		/// </remarks>
		///		
		protected void MiCloseClick(object sender, System.EventArgs e)
		{
			MainForm oParent = (MainForm) this.MdiParent;
			oParent.ActivateChild (this);
			oParent.DoClose();
		}
		
		
		///
		/// <summary>
		/// Create the window's child controls.
		/// </summary>
		/// <remarks>
		/// This method is auto-generated by the form designer IDE.
		/// </remarks>
		///		
		protected void InitializeComponent() {
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(LoggingBaseForm));
			this.imageList1 = new System.Windows.Forms.ImageList(this.components);
			this.miClear = new System.Windows.Forms.MenuItem();
			this.tbbSep1 = new System.Windows.Forms.ToolBarButton();
			this.contextMenu = new System.Windows.Forms.ContextMenu();
			this.tbbFilter = new System.Windows.Forms.ToolBarButton();
			this.panel1 = new System.Windows.Forms.Panel();
			this.panel2 = new System.Windows.Forms.Panel();
			this.tbbPause = new System.Windows.Forms.ToolBarButton();
			this.menuItem8 = new System.Windows.Forms.MenuItem();
			this.miSave = new System.Windows.Forms.MenuItem();
			this.sleepTimer = new System.Windows.Forms.Timer(this.components);
			this.menuItem5 = new System.Windows.Forms.MenuItem();
			this.tbbClear = new System.Windows.Forms.ToolBarButton();
			this.miCopy = new System.Windows.Forms.MenuItem();
			this.menuItem3 = new System.Windows.Forms.MenuItem();
			this.tbbUnpause = new System.Windows.Forms.ToolBarButton();
			this.miClose = new System.Windows.Forms.MenuItem();
			this.miReload = new System.Windows.Forms.MenuItem();
			this.tbbScrollLock = new System.Windows.Forms.ToolBarButton();
			this.miPause = new System.Windows.Forms.MenuItem();
			this.timer = new System.Windows.Forms.Timer(this.components);
			this.tbbSep2 = new System.Windows.Forms.ToolBarButton();
			this.toolBar1 = new System.Windows.Forms.ToolBar();
			this.SuspendLayout();
			// 
			// imageList1
			// 
			this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
			this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
			this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// miClear
			// 
			this.miClear.Index = 1;
			this.miClear.Text = "C&lear";
			this.miClear.Click += new System.EventHandler(this.MiClearClick);
			// 
			// tbbSep1
			// 
			this.tbbSep1.Style = System.Windows.Forms.ToolBarButtonStyle.Separator;
			this.tbbSep1.Visible = false;
			// 
			// contextMenu
			// 
			this.contextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
						this.miCopy,
						this.miClear,
						this.menuItem3,
						this.miPause,
						this.menuItem5,
						this.miSave,
						this.miReload,
						this.menuItem8,
						this.miClose});
			// 
			// tbbFilter
			// 
			this.tbbFilter.ImageIndex = 6;
			this.tbbFilter.Style = System.Windows.Forms.ToolBarButtonStyle.ToggleButton;
			this.tbbFilter.ToolTipText = "Apply a filter to the current text and to future lines";
			// 
			// panel1
			// 
			this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
						| System.Windows.Forms.AnchorStyles.Left)));
			this.panel1.BackColor = System.Drawing.Color.DimGray;
			this.panel1.Location = new System.Drawing.Point(25, 0);
			this.panel1.Name = "panel1";
			this.panel1.Size = new System.Drawing.Size(1, 235);
			this.panel1.TabIndex = 3;
			// 
			// panel2
			// 
			this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
						| System.Windows.Forms.AnchorStyles.Left) 
						| System.Windows.Forms.AnchorStyles.Right)));
			this.panel2.BackColor = System.Drawing.Color.Black;
			this.panel2.DockPadding.Left = 4;
			this.panel2.DockPadding.Top = 4;
			this.panel2.Location = new System.Drawing.Point(26, 0);
			this.panel2.Name = "panel2";
			this.panel2.Size = new System.Drawing.Size(122, 235);
			this.panel2.TabIndex = 1;
			// 
			// tbbPause
			// 
			this.tbbPause.ImageIndex = 4;
			this.tbbPause.ToolTipText = "Stop logging";
			// 
			// menuItem8
			// 
			this.menuItem8.Index = 7;
			this.menuItem8.Text = "-";
			// 
			// miSave
			// 
			this.miSave.Index = 5;
			this.miSave.Text = "&Save...";
			this.miSave.Click += new System.EventHandler(this.MiSaveClick);
			// 
			// sleepTimer
			// 
			this.sleepTimer.Interval = 5000;
			this.sleepTimer.Tick += new System.EventHandler(this.SleepTimerTick);
			// 
			// menuItem5
			// 
			this.menuItem5.Index = 4;
			this.menuItem5.Text = "-";
			// 
			// tbbClear
			// 
			this.tbbClear.ImageIndex = 5;
			this.tbbClear.ToolTipText = "Clears the contents of this log window (Del)";
			// 
			// miCopy
			// 
			this.miCopy.Index = 0;
			this.miCopy.Text = "&Copy";
			this.miCopy.Click += new System.EventHandler(this.MiCopyClick);
			// 
			// menuItem3
			// 
			this.menuItem3.Index = 2;
			this.menuItem3.Text = "-";
			// 
			// tbbUnpause
			// 
			this.tbbUnpause.ImageIndex = 2;
			this.tbbUnpause.ToolTipText = "Start logging";
			this.tbbUnpause.Visible = false;
			// 
			// miClose
			// 
			this.miClose.Index = 8;
			this.miClose.Text = "Cl&ose";
			this.miClose.Click += new System.EventHandler(this.MiCloseClick);
			// 
			// miReload
			// 
			this.miReload.Index = 6;
			this.miReload.Text = "Load enti&re file";
			this.miReload.Click += new System.EventHandler(this.MiReloadClick);
			// 
			// tbbScrollLock
			// 
			this.tbbScrollLock.ImageIndex = 10;
			this.tbbScrollLock.Style = System.Windows.Forms.ToolBarButtonStyle.ToggleButton;
			this.tbbScrollLock.ToolTipText = "Stop scrolling";
			// 
			// miPause
			// 
			this.miPause.Index = 3;
			this.miPause.Text = "S&top";
			this.miPause.Click += new System.EventHandler(this.MiPauseClick);
			// 
			// timer
			// 
			this.timer.Interval = 1000;
			this.timer.Tick += new System.EventHandler(this.TimerTick);
			// 
			// tbbSep2
			// 
			this.tbbSep2.Style = System.Windows.Forms.ToolBarButtonStyle.Separator;
			this.tbbSep2.Visible = false;
			// 
			// toolBar1
			// 
			this.toolBar1.Appearance = System.Windows.Forms.ToolBarAppearance.Flat;
			this.toolBar1.AutoSize = false;
			this.toolBar1.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
						this.tbbScrollLock,
						this.tbbPause,
						this.tbbUnpause,
						this.tbbClear,
						this.tbbSep1,
						this.tbbSep2,
						this.tbbFilter});
			this.toolBar1.Divider = false;
			this.toolBar1.Dock = System.Windows.Forms.DockStyle.Left;
			this.toolBar1.DropDownArrows = true;
			this.toolBar1.ImageList = this.imageList1;
			this.toolBar1.Location = new System.Drawing.Point(0, 0);
			this.toolBar1.Name = "toolBar1";
			this.toolBar1.ShowToolTips = true;
			this.toolBar1.Size = new System.Drawing.Size(25, 235);
			this.toolBar1.TabIndex = 2;
			this.toolBar1.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.ToolBar1ButtonClick);
			// 
			// LoggingBaseForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(32)), ((System.Byte)(32)), ((System.Byte)(32)));
			this.ClientSize = new System.Drawing.Size(148, 235);
			this.Controls.Add(this.panel1);
			this.Controls.Add(this.toolBar1);
			this.Controls.Add(this.panel2);
			this.Resize += new System.EventHandler(this.LoggingBaseFormResize);
			this.Closing += new System.ComponentModel.CancelEventHandler(this.CreatedFormClosing);
			this.Load += new System.EventHandler(this.CreatedFormLoad);
			this.ResumeLayout(false);
		}

		
		
		protected void InitializeComponent2() 
		{
			this.SuspendLayout();
			
			this.txtLog = new SpecialRichTextBox();
			this.txtLog.BackColor = System.Drawing.Color.Black;
			this.txtLog.ForeColor = System.Drawing.Color.LightGray;
			this.txtLog.ContextMenu = this.contextMenu;
			this.txtLog.DetectUrls = false;
			this.txtLog.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
						
			
			this.txtLog.Name = "txtLog";
			
			this.txtLog.TabIndex = 0;
			this.txtLog.Text = "";
			this.txtLog.WordWrap = false;
			this.txtLog.Dock = DockStyle.Fill;
			this.txtLog.BorderStyle = BorderStyle.None;
			
			
			this.txtLog.Location = new Point(0, 0);
			
			
			panel2.Controls.Add(this.txtLog);
						
			this.Closing += new System.ComponentModel.CancelEventHandler(this.OnFormClosing);
		
			this.ResumeLayout(false);
			
			defaultIcon_i = GetDefaultIcon();
			this.Icon = defaultIcon_i;
			sleepyIcon_i = MakeIcon(imageList1.Images[IMG_SLEEPY]);
			this.sleepTimer.Interval = SLEEPY_TIMEOUT;
		}

		
		
		///
		/// <summary>
		/// FormClosing event handler.
		/// </summary>
		/// <remarks>
		/// This event is fired when the form thinks it might be about to close.
		/// It calls the <code>Deinitialise</code> method on each of the active child forms.
		/// </remarks>		
		///
		protected void OnFormClosing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			Deinitialise();		
		}
			
		
		
		
		

		///
		/// <summary>
		/// Creates extra controls for the window.
		/// </summary>
		/// <remarks>
		/// The dummy panel could not be added using the form designer due to 
		/// bugs in the IDE.
		/// </remarks>
		///		
		protected void CreateExtraControls()
		{
			this.dummyPanel = new System.Windows.Forms.Panel();
			this.SuspendLayout();
			this.dummyPanel.Location = new System.Drawing.Point(-50, -50);
			this.dummyPanel.Name = "dummyPanel";
			this.dummyPanel.Size = new System.Drawing.Size(2, 2);
			this.dummyPanel.TabIndex = 0;
			this.Controls.Add(this.dummyPanel);
			this.ResumeLayout(false);
		}
		
		
		///
		/// <summary>
		/// Scrolls to the bottom left of the window.
		/// </summary>
		/// <remarks>
		/// This is a work-around for the way the <code>RichTextBox</code> control handles scrolling.
		/// </remarks>
		///		
		protected void DoScroll()
		{
			//if (! this.ScrollLocked)
			//{
				//Beep();
				//SendMessage (txtLog.Handle.ToInt32(), WM_VSCROLL, SB_BOTTOM, 20);
				//SendMessage (txtLog.Handle.ToInt32(), WM_HSCROLL, SB_LEFT, 0);
			//}
		}		
		
		

    	public static void Beep()
    	{
    		MessageBeep(MessageBeepType.Warning);
    	}
    	
    	
    	public enum MessageBeepType
		{
		    Default = -1,
		    Ok = 0x00000000,
		    Error = 0x00000010,
		    Question = 0x00000020,
		    Warning = 0x00000030,
		    Information = 0x00000040,
		}
		
		[DllImport("user32.dll", SetLastError=true)]
		public static extern bool MessageBeep(
		    MessageBeepType type
		);
		
		
		protected void ToolBar1ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
		{
			if (tbbPause.Equals(e.Button)  ||  tbbUnpause.Equals(e.Button))
			{
				MiPauseClick (sender, e);
			}
			else if (tbbClear.Equals (e.Button))
			{
				MiClearClick (sender, e);				
			}
			else if (tbbFilter.Equals (e.Button))
			{
				MainForm parent = (MainForm) this.MdiParent;
				parent.DoFilter (true);
			}
			else if (tbbScrollLock.Equals (e.Button))
			{
				this.ScrollLocked = (tbbScrollLock.Pushed);
				DoScroll();
			}
			else
			{
				MessageBox.Show ("Unknown button pressed: " + e.Button);
			}
		}
		
		protected void SleepTimerTick(object sender, System.EventArgs e)
		{
			isSleepy_i = true;
			UpdateTitle();
		}
		
	}
}
